
/*-------------------------------------------------------------------------
 *
 * parse_node.h
 *		解析器的内部定义
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/parser/parse_node.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PARSE_NODE_H
#define PARSE_NODE_H

#include "nodes/parsenodes.h"
#include "utils/queryenvironment.h"
#include "utils/relcache.h"


/* 一些在下面声明的结构的前向引用 */
typedef struct ParseState ParseState;
typedef struct ParseNamespaceItem ParseNamespaceItem;
typedef struct ParseNamespaceColumn ParseNamespaceColumn;

/*
 * transformExpr() 识别的表达式类型。许多这些在表达式转换方面并没有语义上的区别；
 * 相反，我们区分它们，以便可以打印出特定上下文的错误消息。
 *
 * 注意：EXPR_KIND_OTHER 在核心代码中未使用，但保留供扩展代码使用
 * 可能需要调用 transformExpr()。核心代码
 * 不会对 EXPR_KIND_OTHER 表达式施加任何基于上下文的限制，
 * 因此调用者必须检查是否需要禁止子查询、聚合、
 * 窗口函数、SRFs 等。
 */
typedef enum ParseExprKind
{
	EXPR_KIND_NONE = 0,			/* “不在表达式中” */
	EXPR_KIND_OTHER,			/* 保留用于扩展 */
	EXPR_KIND_JOIN_ON,			/* JOIN ON */
	EXPR_KIND_JOIN_USING,		/* JOIN USING */
	EXPR_KIND_FROM_SUBSELECT,	/* FROM 子句中的子查询 */
	EXPR_KIND_FROM_FUNCTION,	/* FROM 子句中的函数 */
	EXPR_KIND_WHERE,			/* WHERE */
	EXPR_KIND_HAVING,			/* HAVING */
	EXPR_KIND_FILTER,			/* FILTER */
	EXPR_KIND_WINDOW_PARTITION, /* 窗口定义 PARTITION BY */
	EXPR_KIND_WINDOW_ORDER,		/* 窗口定义 ORDER BY */
	EXPR_KIND_WINDOW_FRAME_RANGE,	/* 带范围的窗口框架子句 */
	EXPR_KIND_WINDOW_FRAME_ROWS,	/* 带行数的窗口框架子句 */
	EXPR_KIND_WINDOW_FRAME_GROUPS,	/* 带组数的窗口框架子句 */
	EXPR_KIND_SELECT_TARGET,	/* SELECT 目标列表项 */
	EXPR_KIND_INSERT_TARGET,	/* INSERT 目标列表项 */
	EXPR_KIND_UPDATE_SOURCE,	/* UPDATE 赋值源项 */
	EXPR_KIND_UPDATE_TARGET,	/* UPDATE 赋值目标项 */
	EXPR_KIND_MERGE_WHEN,		/* MERGE WHEN [NOT] MATCHED 条件 */
	EXPR_KIND_GROUP_BY,			/* 分组依据 */
	EXPR_KIND_ORDER_BY,			/* ORDER BY */
	EXPR_KIND_DISTINCT_ON,		/* DISTINCT ON */
	EXPR_KIND_LIMIT,			/* LIMIT */
	EXPR_KIND_OFFSET,			/* OFFSET */
	EXPR_KIND_RETURNING,		/* RETURNING */
	EXPR_KIND_VALUES,			/* VALUES */
	EXPR_KIND_VALUES_SINGLE,	/* 单行 VALUES（仅在 INSERT 中） */
	EXPR_KIND_CHECK_CONSTRAINT, /* 表的 CHECK 约束 */
	EXPR_KIND_DOMAIN_CHECK,		/* 域的 CHECK 约束 */
	EXPR_KIND_COLUMN_DEFAULT,	/* 表列的默认值 */
	EXPR_KIND_FUNCTION_DEFAULT, /* 函数的默认参数值 */
	EXPR_KIND_INDEX_EXPRESSION, /* 索引表达式 */
	EXPR_KIND_INDEX_PREDICATE,	/* 索引谓词 */
	EXPR_KIND_STATS_EXPRESSION, /* 扩展统计表达式 */
	EXPR_KIND_ALTER_COL_TRANSFORM,	/* ALTER COLUMN TYPE 中的转换表达式 */
	EXPR_KIND_EXECUTE_PARAMETER,	/* EXECUTE 中的参数值 */
	EXPR_KIND_TRIGGER_WHEN,		/* CREATE TRIGGER 中的 WHEN 条件 */
	EXPR_KIND_POLICY,			/* 策略中的 USING 或 WITH CHECK 表达式 */
	EXPR_KIND_PARTITION_BOUND,	/* 分区绑定表达式 */
	EXPR_KIND_PARTITION_EXPRESSION, /* PARTITION BY 表达式 */
	EXPR_KIND_CALL_ARGUMENT,	/* CALL 中的过程参数 */
	EXPR_KIND_COPY_WHERE,		/* WHERE condition in COPY FROM */
	EXPR_KIND_GENERATED_COLUMN, /* 列的生成表达式 */
	EXPR_KIND_CYCLE_MARK,		/* 循环标记值 */
} ParseExprKind;


/*
 * 解析器挂钩的函数签名
 */
typedef Node *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref);
typedef Node *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var);
typedef Node *(*ParseParamRefHook) (ParseState *pstate, ParamRef *pref);
typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
								  Oid targetTypeId, int32 targetTypeMod,
								  int location);


/*
 * 解析分析过程中使用的状态信息
 *
 * parentParseState: 在顶级 ParseState 中为 NULL。当解析子查询时，
 * 链接到外部查询的当前解析状态。
 *
 * p_sourcetext: 生成正在分析的原始解析树的源字符串，如果不可用则为 NULL。
 * （该字符串仅用于生成错误消息中的光标位置：我们需要它将解析结构中的
 * 字节位置转换为字符光标位置。）
 *
 * p_rtable: 将成为查询的范围表的 RTE 列表。
 * 注意，这些条目的 relname 和 refname 并不一定是唯一的；
 * 按名称搜索 rtable 是个坏主意。
 *
 * p_joinexprs: 与 p_rtable 条目相关联的 JoinExpr 节点列表。
 * 这与 p_rtable 一一对应，但对于非连接的 RTE，包含 NULLs，
 * 如果最后的 RTE(s) 不是连接，可能比 p_rtable 短。
 *
 * p_joinlist: 将成为查询顶层 FromExpr 节点的 fromlist 的连接项列表
 * （RangeTblRef 和 JoinExpr 节点）。
 *
 * p_namespace: 代表当前表和列查找的 ParseNamespaceItems 列表。
 * （这里列出的 RTE 可能只是整个 rtable 的一个子集。见下方 ParseNamespaceItem 的
 * 注释。）
 *
 * p_lateral_active: 如果我们当前正在解析此解析级别的 LATERAL 子表达式则为 true。
 * 这使得 p_lateral_only 命名空间项目可见，而当 p_lateral_active 为 FALSE 时
 * 它们不可见。
 *
 * p_ctenamespace: 目前可见的 CommonTableExprs（WITH 项目）列表。
 * 这与 p_namespace 完全不同，因为 CTE 不是 RTE，"可见性"意味着你可以
 * 从中创建一个 RTE。
 *
 * p_future_ctes: 由于作用域规则而尚未可见的 CommonTableExprs（WITH 项目）列表。
 * 这用于帮助改善错误消息。
 *
 * p_parent_cte: 立即包含当前查询的 CommonTableExpr（如果有）。
 *
 * p_target_relation: 目标关系，如果查询是 INSERT/UPDATE/DELETE/MERGE。
 *
 * p_target_nsitem: 目标关系的 ParseNamespaceItem。
 *
 * p_is_insert: true 表示处理赋值表达式如 INSERT，false 表示像 UPDATE 一样处理它们。
 * （注意，这在语句内可能会变化，针对 INSERT ON CONFLICT UPDATE 等情况。）
 *
 * p_windowdefs: 表示 WINDOW 和 OVER 子句的 WindowDefs 列表。
 * 我们在转换表达式时收集这些，然后在之后再转换它们
 * （以便排序/分组子句所需的任何 resjunk tlist 项目最终落在查询 tlist 的末尾）。
 * WindowDef 在该列表中的位置，从 1 开始，是用来引用它的 winref 编号。
 *
 * p_expr_kind: 我们当前正在解析的表达式种类，如上面的枚举；
 * 当不在表达式中时为 EXPR_KIND_NONE。
 *
 * p_next_resno: 下一个要分配的 TargetEntry.resno，从 1 开始。
 *
 * p_multiassign_exprs: 部分处理的 MultiAssignRef 源表达式。
 *
 * p_locking_clause: 查询的 FOR UPDATE/FOR SHARE 子句（如果有）。
 *
 * p_locked_from_parent: 如果父查询级别对此子查询整体应用 FOR UPDATE/SHARE 则为 true。
 *
 * p_resolve_unknowns: 将未知类型 SELECT 输出列解析为 TEXT 类型
 * （默认为 true）。
 *
 * p_hasAggs, p_hasWindowFuncs 等: 如果在查询中找到了任何指示的构造则为 true。
 *
 * p_last_srf: 最近在查询中找到的返回集合的 FuncExpr 或 OpExpr，
 * 如果没有则为 NULL。
 *
 * p_pre_columnref_hook 等: 可选的解析器挂钩函数，用于修改 ColumnRefs
 * 和 ParamRefs 的解析。
 *
 * p_ref_hook_state: 传递解析器挂钩函数的状态。
 */
struct ParseState
{
	ParseState *parentParseState;	/* 栈链接 */
	const char *p_sourcetext;	/* 源文本，如果不可用则为 NULL */
	List	   *p_rtable;		/* 到目前为止的范围表 */
	List	   *p_joinexprs;	/* RTE_JOIN p_rtable 条目的 JoinExprs */
	List	   *p_joinlist;		/* 到目前为止的连接项（将成为 FromExpr
								 * 节点的 fromlist） */
	List	   *p_namespace;	/* 当前可引用的 RTEs（ParseNamespaceItem 的列表） */
	bool		p_lateral_active;	/* p_lateral_only 项目可见？ */
	List	   *p_ctenamespace; /* 当前用于公共表表达式的命名空间 */
	List	   *p_future_ctes;	/* 尚未在命名空间中的公共表表达式 */
	CommonTableExpr *p_parent_cte;	/* 此查询包含的 CTE */
	Relation	p_target_relation;	/* INSERT/UPDATE/DELETE/MERGE 目标关系 */
	ParseNamespaceItem *p_target_nsitem;	/* 目标关系的 NSItem，或 NULL */
	bool		p_is_insert;	/* 像 INSERT 一样处理赋值而不是 UPDATE */
	List	   *p_windowdefs;	/* 窗口子句的原始表示 */
	ParseExprKind p_expr_kind;	/* 我们正在解析什么类型的表达式 */
	int			p_next_resno;	/* 下一个要分配的目标列表 resno */
	List	   *p_multiassign_exprs;	/* 多赋值的垃圾 tlist 项目 */
	List	   *p_locking_clause;	/* 原始 FOR UPDATE/FOR SHARE 信息 */
	bool		p_locked_from_parent;	/* 父级已将此子查询标记为
										 * FOR UPDATE/FOR SHARE */
	bool		p_resolve_unknowns; /* 将未知类型的 SELECT 输出解析为
									 * 文本类型 */

	QueryEnvironment *p_queryEnv;	/* 当前环境，包括对外部环境的引用 */

	/* 标志指示在查询中发现的内容： */
	bool		p_hasAggs;
	bool		p_hasWindowFuncs;
	bool		p_hasTargetSRFs;
	bool		p_hasSubLinks;
	bool		p_hasModifyingCTE;

	Node	   *p_last_srf;		/* 最近找到的返回集合的函数/操作 */

	/*
	 * 可选的钩子函数，用于解析器回调。除非
	 * 由 make_parsestate 的调用者设置，否则为 null。
	 */
	PreParseColumnRefHook p_pre_columnref_hook;
	PostParseColumnRefHook p_post_columnref_hook;
	ParseParamRefHook p_paramref_hook;
	CoerceParamHook p_coerce_param_hook;
	void	   *p_ref_hook_state;	/* 以上内容的常见通行链接 */
};

/*
 * 名称空间列表的一个元素。
 *
 * p_names 包含此 nsitem 所暴露的表名和列名。
 * （通常等于 p_rte->eref，但对于 JOIN USING 别名，其值
 * 等于 p_rte->join_using_alias。由于 USING 列将是
 * 连接的前 N 列，因此实际效果是我们仅通过此 nsitem 
 * 暴露这些连接列。）
 *
 * p_rte 和 p_rtindex 链接到底层的 rangetable 条目。
 *
 * p_nscolumns 数组包含显示如何构造引用 p_names->colnames 
 * 列表中名称的 Vars 的信息。
 *
 * 具有 p_rel_visible 设置的名称空间项定义了哪些 RTE 
 * 可以通过限定名称访问，而具有 p_cols_visible 设置的则定义了
 * 哪些 RTE 可以通过非限定名称访问。因为没有别名的 JOIN 
 * 不会隐藏包含的表（因此它们必须对于限定引用是可见的），
 * 但它会隐藏其列（对列的非限定引用指的是 JOIN，而不是成员
 * 表，因此我们必须不抱怨这样的引用是模糊的）。
 * 诸如 NEW/OLD 等各种特殊 RTE 也可能只出现一个标志设置。
 *
 * 在处理 FROM 子句时，名称空间项可能出现 p_lateral_only 设置，
 * 这意味着它们仅对 LATERAL 子表达式可见。
 * （pstate 的 p_lateral_active 标志指示我们此时是否在这样的子表达式内。）
 * 如果未设置 p_lateral_ok，则实际使用这样的名称空间项是错误的。
 * 人们可能会认为最好完全排除这些项的可见性，但 SQL:2008 
 * 的措辞要求我们以这种方式操作。我们还使用 p_lateral_ok 
 * 禁止 LATERAL 对 UPDATE/DELETE 目标表的引用。
 *
 * 在任何时候，名称空间列表不应包含根据 checkNameSpaceConflicts 
 * 规则冲突的两个条目；但请注意，这些规则比“必须具有不同的别名” 
 * 要复杂得多，因此在实践中，搜索名称空间列表的代码必须检查模糊的引用。
 */
struct ParseNamespaceItem
{
	Alias	   *p_names;		/* 表和列名 */
	RangeTblEntry *p_rte;		/* 关系的 rangetable 条目 */
	int			p_rtindex;		/* 关系在 rangetable 中的索引 */
	/* 与 p_names->colnames 长度相同的数组： */
	ParseNamespaceColumn *p_nscolumns;	/* 每列数据 */
	bool		p_rel_visible;	/* 关系名称可见？ */
	bool		p_cols_visible; /* 列名可作为非限定引用可见？ */
	bool		p_lateral_only; /* 仅对 LATERAL 表达式可见？ */
	bool		p_lateral_ok;	/* 如果是，连接类型是否允许使用？ */
};

/*
 * 有关 ParseNamespaceItem 中一列的数据。
 *
 * 我们跟踪构造引用列的 Var 所需的信息
 * （但仅用于用户定义的列；系统列引用和
 * 整行引用单独处理）。
 *
 * p_varno 和 p_varattno 标识语义引用项，除非引用的是
 * 连接 USING 列，该列在语义上与任何连接输入列不等价 
 * （因为它是全连接或输入列需要类型强制转换）。在这些情况下， 
 * p_varno 和 p_varattno 指的是 JOIN RTE。
 *
 * p_varnosyn 和 p_varattnosyn 要么与 p_varno/p_varattno 相同，
 * 要么它们指定在隐藏语义引用 RTE 的别名 JOIN RTE 中的列的位置。
 * （这可以是此 ParseNamespaceColumn 条目存在的 JOIN RTE，
 * 或某个更低的连接级别。）
 *
 * 如果一个 RTE 包含一个已删除的列，则其 ParseNamespaceColumn 
 * 结构全为零。（惯例是测试 p_varno == 0 来检测这一点。）
 */
struct ParseNamespaceColumn
{
	Index		p_varno;		/* rangetable 索引 */
	AttrNumber	p_varattno;		/* 列的属性编号 */
	Oid			p_vartype;		/* pg_type OID */
	int32		p_vartypmod;	/* 类型修改器值 */
	Oid			p_varcollid;	/* collation 的 OID，或 InvalidOid */
	Index		p_varnosyn;		/* 语法引用的 rangetable 索引 */
	AttrNumber	p_varattnosyn;	/* 语法引用的属性编号 */
	bool		p_dontexpand;	/* 不包含在星号扩展中 */
};

/* 支持 parser_errposition_callback 函数 */
typedef struct ParseCallbackState
{
	ParseState *pstate;
	int			location;
	ErrorContextCallback errcallback;
} ParseCallbackState;


extern ParseState *make_parsestate(ParseState *parentParseState);
extern void free_parsestate(ParseState *pstate);
extern int	parser_errposition(ParseState *pstate, int location);

extern void setup_parser_errposition_callback(ParseCallbackState *pcbstate,
											  ParseState *pstate, int location);
extern void cancel_parser_errposition_callback(ParseCallbackState *pcbstate);

extern void transformContainerType(Oid *containerType, int32 *containerTypmod);

extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate,
													 Node *containerBase,
													 Oid containerType,
													 int32 containerTypMod,
													 List *indirection,
													 bool isAssignment);
extern Const *make_const(ParseState *pstate, A_Const *aconst);

#endif							/* PARSE_NODE_H */
